package com.linkoog.devtools.intellij.ui.tree;

import com.intellij.ide.TreeExpander;
import com.intellij.openapi.Disposable;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.ui.components.JBLoadingPanel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ui.JBUI;
import jdk.jfr.Description;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;

public class ListTreePanel extends JBLoadingPanel implements Disposable, TreeExpander {

    @Getter
    protected final JTree tree;

    @Setter
    @Description("节点选中事件")
    protected BiConsumer<JTree, TreeNode> chooseListener;
    @Setter
    @Description("节点双击事件")
    protected BiConsumer<JTree, TreeNode> doubleClickListener;
    @Setter
    @Description("节点右键菜单")
    protected BiFunction<MouseEvent, TreeNode, JPopupMenu> rightClickMenuProvider;


    public ListTreePanel(@NotNull final JTree tree, TreeCellRenderer treeCellRenderer, Disposable parentDisposable) {
        super(new BorderLayout(),  parentDisposable);
        this.tree = tree;
        this.tree.setRootVisible(true);
        this.tree.setShowsRootHandles(true);
        this.tree.createToolTip();
        this.tree.setCellRenderer(treeCellRenderer);
        this.add(createJBScrollPane(), BorderLayout.CENTER);

        this.tree.addTreeSelectionListener(e -> {
            if (!tree.isEnabled()) {
                return;
            }
            TreeNode treeNode = (TreeNode)tree.getLastSelectedPathComponent();
            if (treeNode == null){
                return;
            }
            if (chooseListener != null){
                chooseListener.accept(tree, treeNode);
            }
        });

        this.tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent event) {
                if (!tree.isEnabled()) {
                    return;
                }
                TreeNode treeNode = getNode(event);
                if (Objects.isNull(treeNode)) {
                    return;
                }

                if (SwingUtilities.isLeftMouseButton(event)) {
                    if (isDoubleClick(event) && doubleClickListener != null) {
                        doubleClickListener.accept(tree, treeNode);
                    }
                } else if (SwingUtilities.isRightMouseButton(event) && rightClickMenuProvider != null) {
                    JPopupMenu popupMenu = rightClickMenuProvider.apply(event, treeNode);
                    if (popupMenu != null) showPopupMenu(event.getX(), event.getY(), popupMenu);
                }
            }

            public static boolean isDoubleClick(MouseEvent e) {
                return e != null && e.getClickCount() > 0 && e.getClickCount() % 2 == 0;
            }

            @Nullable
            private TreeNode getNode(@NotNull MouseEvent event) {
                TreePath treePath = tree.getPathForLocation(event.getX(), event.getY());
                tree.setSelectionPath(treePath);
                Object selectedNode;
                if (treePath != null) {
                    selectedNode = treePath.getLastPathComponent();
                } else {
                    selectedNode = tree.getLastSelectedPathComponent();
                }
                return (TreeNode)selectedNode;
            }
        });
    }

    protected JBScrollPane createJBScrollPane() {
        JBScrollPane scrollPane = new JBScrollPane();
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setBorder(JBUI.Borders.customLineTop(new JBColor(Gray._214, new Color(30, 31, 34))));
        scrollPane.setViewportView(tree);
        return scrollPane;
    }


    protected void showPopupMenu(int x, int y, @Nullable JPopupMenu menu) {
        if (menu == null) {
            return;
        }
        TreePath path = tree.getPathForLocation(x, y);
        tree.setSelectionPath(path);
        Rectangle rectangle = tree.getUI().getPathBounds(tree, path);
        if (rectangle != null && rectangle.contains(x, y)) {
            menu.show(tree, x, rectangle.y + rectangle.height);
        }
    }

    @Override
    public void dispose() {

    }

    @Override
    public boolean canExpand() {
        return tree.getRowCount() > 0;
    }

    @Override
    public boolean canCollapse() {
        return tree.getRowCount() > 0;
    }

    @Override
    public void expandAll() {
        expandOrCollapse(new TreePath(tree.getModel().getRoot()), true);
    }

    @Override
    public void collapseAll() {
        expandOrCollapse(new TreePath(tree.getModel().getRoot()), false);
    }

    private void expandOrCollapse(@NotNull TreePath parent, boolean expandOrCollapse) {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) parent.getLastPathComponent();
        if (node.getChildCount() >= 0) {
            for (Enumeration<?> e = node.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode) e.nextElement();
                TreePath path = parent.pathByAddingChild(n);
                expandOrCollapse(path, expandOrCollapse);
            }
        }

        // 展开或收起,必须自下而上进行
        if (expandOrCollapse) {
            tree.expandPath(parent);
        } else {
            tree.collapsePath(parent);
        }
    }





}
